package frontend.pages.worklog.monthly;

import backend.model.admin.Employee;
import frontend.model.admin.CalendarDayUIModel;
import frontend.model.worklog.WorkLogUIModel;
import frontend.components.other.EmployeeSelectionPanel;
import frontend.core.TimeTrackingWebSession;
import shared.util.CalendarUtils;
import frontend.components.other.UserInputCallableAction;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.request.resource.ContextRelativeResource;

import static frontend.pages.worklog.monthly.DisplayMonthBuilder.*;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

public class MonthlyWorkLogPanel extends Panel {

    private WebMarkupContainer workLogFormContainer;
    private WebMarkupContainer container;
    private EmployeeSelectionPanel employeeSelectionPanel;
    private List<CalendarDayPanel> calendarDayPanelList;
    private Employee employee;

    public MonthlyWorkLogPanel(String id, Employee employee) {
        super(id);
        this.setOutputMarkupId(true);
        this.employee = employee;

        initComponents();
    }

    private void initComponents() {
        buildWorkLogFormContainer();
        buildEmployeeAndCalendarFrame();
        Calendar firstDayOfSelectedMonth = TimeTrackingWebSession.getSession().getFirstDayOfSelectedMonth();
        buildHeader(firstDayOfSelectedMonth);
        buildMonthCalendar(container, firstDayOfSelectedMonth);

    }

    private void buildWorkLogFormContainer() {
        workLogFormContainer = new WebMarkupContainer("workLogFormContainer");
        workLogFormContainer.setOutputMarkupId(true);
        workLogFormContainer.setOutputMarkupPlaceholderTag(true);
        add(workLogFormContainer);
    }

    private void buildMonthCalendar(WebMarkupContainer frame, Calendar monthStart) {
        frame.add(createDaysOfWeekLabels());
        buildWeeks(frame, DisplayMonthBuilder.getDisplayWeeks(monthStart));
    }

    private void buildHeader(Calendar monthStart) {
        workLogFormContainer.add(new Label("currentMonth", getMonthNameLabel(monthStart)));
        workLogFormContainer.add(createNextMonthLink());
        workLogFormContainer.add(createPreviousMonthLink());
        employeeSelectionPanel = new EmployeeSelectionPanel("employeeSelectionPanel", new WorkLogUIModel(employee),
                createOnSelectionChangeAction(), "pages.monthlyWorkLogPage.employee", false);
        workLogFormContainer.add(employeeSelectionPanel);
    }

    private WebMarkupContainer createDaysOfWeekLabels() {
        WebMarkupContainer daysOfWeek = new WebMarkupContainer("daysOfWeek");
        daysOfWeek.add(new Label("monday", getDayOfWeekLabel(Calendar.MONDAY)));
        daysOfWeek.add(new Label("tuesday", getDayOfWeekLabel(Calendar.TUESDAY)));
        daysOfWeek.add(new Label("wednesday", getDayOfWeekLabel(Calendar.WEDNESDAY)));
        daysOfWeek.add(new Label("thursday", getDayOfWeekLabel(Calendar.THURSDAY)));
        daysOfWeek.add(new Label("friday", getDayOfWeekLabel(Calendar.FRIDAY)));
        daysOfWeek.add(new Label("saturday", getDayOfWeekLabel(Calendar.SATURDAY)));
        daysOfWeek.add(new Label("sunday", getDayOfWeekLabel(Calendar.SUNDAY)));
        return daysOfWeek;
    }

    private String getMonthNameLabel(Calendar monthStart) {
        String monthNameResourceKey = CalendarUtils.getMonthResourceKey(monthStart.get(Calendar.MONTH));
        int year = monthStart.get(Calendar.YEAR);
        return new ResourceModel(monthNameResourceKey).getObject() + " " + year;
    }

    private String getDayOfWeekLabel(int day) {
        return new ResourceModel(CalendarUtils.getDayOfWeekResourceKey(day)).getObject();
    }

    private void buildWeeks(WebMarkupContainer calendarFrame, List<DisplayableWeek> weeks) {
        calendarDayPanelList = new ArrayList<CalendarDayPanel>();

        ListView<DisplayableWeek> weeksList = new ListView<DisplayableWeek>("weeks", weeks) {

            @Override
            protected void populateItem(ListItem<DisplayableWeek> item) {
                DisplayableWeek week = item.getModelObject();
                Map<Integer, Calendar> dayOfWeekToDataMap = week.getDayOfWeekToDayOfMonthMap();

                int dayIndex = 1;
                for (Integer day : dayOfWeekToDataMap.keySet()) {
                    Calendar dayOfMonth = dayOfWeekToDataMap.get(day);

                    String panelId = "day" + dayIndex;
                    if (dayOfMonth == null) {
                        item.add(new EmptyDayPanel(panelId));
                    } else {
                        CalendarDayUIModel dayModel = new CalendarDayUIModel(dayOfMonth, employee);
                        CalendarDayPanel calendarDayPanel = new CalendarDayPanel(panelId, dayModel);
                        item.add(calendarDayPanel);
                        calendarDayPanelList.add(calendarDayPanel);
                    }

                    dayIndex ++;
                }
                item.setOutputMarkupId(true);

            }
        };
        calendarFrame.add(weeksList);
    }

    public void reloadCalendarData(AjaxRequestTarget target, Employee employee) {
        this.employee = employee;
        refreshCalendar(target, TimeTrackingWebSession.getSession().getFirstDayOfSelectedMonth());
    }

    private AjaxLink<Void> createNextMonthLink() {
        ChangeMonthLink link = new ChangeMonthLink("nextMonthLink", 1);
        link.add(new Image("nextMonthImg", new ContextRelativeResource("images/icon_set/16/Arrow3-Right.png")));
        return link;
    }

    private AjaxLink<Void> createPreviousMonthLink() {
        ChangeMonthLink link = new ChangeMonthLink("previousMonthLink", -1);
        link.add(new Image("previousMonthImg",  new ContextRelativeResource("images/icon_set/16/Arrow3-Left.png")));
        return link;
    }

    private void buildEmployeeAndCalendarFrame() {
        container = new WebMarkupContainer("calendarFrame");
        container.setOutputMarkupId(true);

        add(container);
    }

    public void refreshCalendar(AjaxRequestTarget ajaxRequestTarget, Calendar firstDayOfMonth) {
        this.remove(workLogFormContainer);
        this.remove(container);

        initComponents();

        ajaxRequestTarget.add(this);
    }

    class ChangeMonthLink extends AjaxLink<Void> {
        private int monthChange;

        public ChangeMonthLink(String id, int monthChange) {
            super(id);
            this.monthChange = monthChange;
        }

        @Override
        public void onClick(AjaxRequestTarget target) {
            Calendar firstDayOfSelectedMonth = TimeTrackingWebSession.getSession().getFirstDayOfSelectedMonth();
            firstDayOfSelectedMonth.add(Calendar.MONTH, monthChange);
            firstDayOfSelectedMonth.set(Calendar.DATE, 1);
            TimeTrackingWebSession.getSession().setFirstDayOfSelectedMonth(firstDayOfSelectedMonth);

            refreshCalendar(target, firstDayOfSelectedMonth);
        }
    }

    private UserInputCallableAction<Employee> createOnSelectionChangeAction() {
        return new UserInputCallableAction<Employee>() {
            @Override
            public void call(AjaxRequestTarget target, Employee selectedEmployee) {
                reloadCalendarData(target, selectedEmployee);
            }
        };
    }
}
